package com.lagou.niancheng.mvc.dispatcher.core;

import com.lagou.niancheng.mvc.dispatcher.annotations.MyRequestMapping;
import com.lagou.niancheng.mvc.dispatcher.annotations.MyRequestParam;
import com.lagou.niancheng.mvc.dispatcher.annotations.MySecure;
import com.lagou.niancheng.mvc.dispatcher.entity.RequestMappingMetaData;
import com.lagou.niancheng.mvc.dispatcher.entity.ScannedClassMetaData;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * 请求映射注册中心
 *
 * @description: default
 * @author: 阿秋@niancheng
 * @date: 2020/4/8
 */
public class MyRequestMappingRegistry {

    private List<RequestMappingMetaData> requestMappingMetaDataList;

    /**
     * 注册请求mapping
     *
     * @param scannedClassMetaDataList 所有被扫描过的类信息
     */
    public void registryRequestMapping(List<ScannedClassMetaData> scannedClassMetaDataList) {
        scannedClassMetaDataList.stream()
                .filter(ScannedClassMetaData::isController)
                .forEach(this::parseClassMetaData);
    }

    private void parseClassMetaData(ScannedClassMetaData scannedClassMetaData) {
        Class beanType = scannedClassMetaData.getBeanType();
        String beanName = scannedClassMetaData.getBeanName();
        // 从类上获取url前缀
        String urlPrefix = getUrlFromClass(beanType);
        // 从类上获取username数组
        String[] usernames = getUsernameFromClass(beanType);
        // 获取到所有的方法
        Method[] declaredMethods = beanType.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            // 解析方法
            parseMethod(declaredMethod, beanName, urlPrefix, usernames);
        }
    }

    private String[] getUsernameFromClass(Class beanType) {
        MySecure mySecure = (MySecure) beanType.getAnnotation(MySecure.class);
        if (mySecure == null) {
            return null;
        }
        return mySecure.username();
    }

    private String getUrlFromClass(Class beanType) {
        MyRequestMapping myRequestMapping = (MyRequestMapping) beanType.getAnnotation(MyRequestMapping.class);
        if (myRequestMapping == null) {
            return null;
        }
        return myRequestMapping.value();
    }

    private void parseMethod(Method declaredMethod, String beanName, String urlPrefix, String[] usernames) {
        // 获取到方法上的MyRequestMapping注解
        MyRequestMapping requestMapping = declaredMethod.getAnnotation(MyRequestMapping.class);
        if (requestMapping == null) {
            return;
        }
        RequestMappingMetaData requestMappingMetaData = new RequestMappingMetaData();
        // 拼接请求路径
        String url = urlPrefix + requestMapping.value();
        // 获取所有用户名
        Set<String> usernameList = getUsernameFromMethod(declaredMethod, usernames);
        // 获取参数映射
        Map<String, Integer> paramIndexMap = getParamMap(declaredMethod);

        requestMappingMetaData.setSecureList(usernameList);
        requestMappingMetaData.setBeanName(beanName);
        requestMappingMetaData.setUrlPattern(Pattern.compile(url));
        requestMappingMetaData.setMappingMethod(declaredMethod);
        requestMappingMetaData.setParamIndexMap(paramIndexMap);
        // 添加到注册列表中
        addRequestMapping(requestMappingMetaData);
    }

    private void addRequestMapping(RequestMappingMetaData requestMappingMetaData) {
        if (requestMappingMetaDataList == null) {
            requestMappingMetaDataList = new ArrayList<>();
        }
        requestMappingMetaDataList.add(requestMappingMetaData);
    }

    private Map<String, Integer> getParamMap(Method declaredMethod) {
        Parameter[] parameters = declaredMethod.getParameters();
        if (parameters == null) {
            return Collections.emptyMap();
        }
        Map<String, Integer> paramIndexMap = new HashMap<>(parameters.length);
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            MyRequestParam requestParam = parameter.getAnnotation(MyRequestParam.class);
            String paramName = parameter.getName();
            if (requestParam != null) {
                paramName = requestParam.value();
            }
            paramIndexMap.put(paramName, i);
        }
        return paramIndexMap;
    }

    private Set<String> getUsernameFromMethod(Method declaredMethod, String[] usernames) {
        Set<String> usernameList = new HashSet<>();
        if (usernames != null) {
            usernameList.addAll(Arrays.asList(usernames));
        }
        MySecure mySecure = declaredMethod.getAnnotation(MySecure.class);
        if (mySecure != null) {
            usernameList.addAll(Arrays.asList(mySecure.username()));
        }
        return usernameList;
    }

    /**
     * 根据请求url获取请求映射bean
     *
     * @param requestUrl 请求url
     * @return 返回匹配的请求映射逻辑
     */
    public RequestMappingMetaData getRequestMappingBean(String requestUrl) {
        if (requestMappingMetaDataList == null) {
            return null;
        }
        for (RequestMappingMetaData requestMappingMetaData : requestMappingMetaDataList) {
            if (requestMappingMetaData.getUrlPattern().matcher(requestUrl).matches()) {
                return requestMappingMetaData;
            }
        }
        return null;
    }


}
